package own.stu.jobgib.playown.juc.completable;

import com.google.common.base.Stopwatch;
import io.netty.channel.DefaultEventLoop;
import io.netty.util.concurrent.GenericFutureListener;
import io.netty.util.concurrent.Promise;
import lombok.extern.slf4j.Slf4j;
import org.redisson.misc.AsyncSemaphore;

import java.util.concurrent.*;

/**
 * listener vs compelet
 */
@Slf4j
public class FutureListenerTest {


    public static void main(String[] args) throws ExecutionException, InterruptedException {

        // testBreakWithLabel();

        /*testBreakWithLabel_2(null, "x");
        log.info(" -------- ");
        testBreakWithLabel_2(null, null);*/

        testCompletableFutureVsFutureWithListener();
    }

    public static void testCompletableFutureVsFutureWithListener() throws ExecutionException, InterruptedException {

        ExecutorService executorService = Executors.newFixedThreadPool(4);
        final ThreadLocalRandom random = ThreadLocalRandom.current();
//        Promise<Object> promise = ImmediateEventExecutor.INSTANCE.newPromise();

        final Stopwatch watcher = Stopwatch.createStarted();

        // FutureTask
        final Future<Integer> resultFuture = executorService.submit(() -> {
            log.info("execute callable task {}", watcher.elapsed());
            TimeUnit.MILLISECONDS.sleep(random.nextInt(100, 200));
            return -1;
        });
        log.info("result : {}, {}", resultFuture.get(), watcher.elapsed());
        log.info(" ----------  ");

        final DefaultEventLoop eventExecutors = new DefaultEventLoop();
        final io.netty.util.concurrent.Future<String> future = eventExecutors.newSucceededFuture("result - successdFuture");
        future.addListener(new GenericFutureListener<io.netty.util.concurrent.Future<? super String>>() {
            @Override
            public void operationComplete(io.netty.util.concurrent.Future<? super String> future) throws Exception {
                log.info("this is successdFuture.listener#operateComplete");
            }
        });
        log.info(" ---------- {}", future.get());

        watcher.reset();
        // promise 在future基础上添加了 listener, 这种模式很直接，在设置了结果之后，会调用 listener的逻辑
        final Promise<Object> newPromise = eventExecutors.newPromise();
        executorService.submit(() -> {
            log.info("execute some task {}", watcher.elapsed());
            TimeUnit.MILLISECONDS.sleep(random.nextInt(100, 200));
            newPromise.setSuccess(-1);
            return -1;
        });

        newPromise.addListener(fu -> {
            log.info("this is successdFuture.listener#operateComplete {}", fu.getNow());
        });

        log.info(" ---------- {}", future.get());

        watcher.reset();
        log.info(" ===================================================== ");
        log.info(" ================= CompletableFuture ================= ");
        log.info(" ===================================================== ");

        AsyncSemaphore asyncSemaphore = new AsyncSemaphore(1);
        final CompletableFuture<String> promise = new CompletableFuture();
        executorService.submit(() -> {
            asyncSemaphore.acquire().thenAccept(r -> {
                if (promise.isDone()) {
                    asyncSemaphore.release();
                    return;
                }
                try {
                    // TimeUnit.MILLISECONDS.sleep(random.nextInt(100, 200));
                    TimeUnit.MINUTES.sleep(random.nextInt(100, 200));
                    promise.complete("hello compleableFuture");
                } catch (InterruptedException e) {
                    log.error(" - ---- ", e);
                    promise.completeExceptionally(e);
                }
                asyncSemaphore.release();
            });
        });

        promise.thenAccept(v -> {
            log.info("like listener action {}", watcher.toString());
        });

        executorService.shutdown();
        eventExecutors.shutdownGracefully();
    }

    private static void testBreakWithLabel_2(String result, String condition) {

        tryComplete:
        if (result == null) {
            if (condition != null) {
                log.info("condition is not null");
                break tryComplete;
            }
            try {
                log.info(" do sth ");
            } catch (Throwable ex) {
                log.error(" throw ", ex);
            }
        }
    }

    private static void testBreakWithLabel() {
        label1:
        for (int i = 0; i < 10; i++) {
            label2:
            if (i > 0) {
                if (i > 8) {
                    break label1;
                }
                System.out.print(i + " ");
                if (i > 3) {
                    break label2;
                }
                System.out.print(" if end ");

            }

            label3:
            {
                if (i > 5) {
                    break label3;
                }
                System.out.print(", label3 block");
            }
            System.out.println(", for end ");
        }
    }
}
